import { Graphics } from "pixi.js";
import { useIntervalFn } from "@vueuse/core";
import { TileMap } from "./Tiles";
import { NamedSet } from "../utils/NamedSet";
import { DataDiff, Meta } from "../Data/Meta";
import { DataController } from "../Data/DataController";
import { AsBlendColors } from "../../../assembly/AsBlendColors";
export const DrawingController = useIntervalFn(() => {
    reDrawCollection.forEach((i) => i());
    if (onceReDrawCall.size) {
        onceReDrawCall.forEach((i) => i());
        onceReDrawCall.clear();
    }
}, 16);
/** 每次更新固定的事件 */
const reDrawCollection = new Set<Function>();
/** 当次更新有效，然后被清除 */
const onceReDrawCall = new Set<Function>();
export const nextReDrawTick = (...args: Function[]) => {
    args.forEach((i) => {
        onceReDrawCall.add(i);
    });
};

export const createDataCache = () => {
    return new NamedSet<DataDiff>(
        (i) => i.position.join(),
        // 数据发生冲突时，对前后数据进行接龙整合
        (dataCache, Map, oldKey, newData) => {
            const item = Map.get(oldKey)!;
            const index = dataCache.indexOf(item);
            // 接龙
            //! 注意，写入的数据是不能被改变的，原始的数据可以改变
            // 移动这个数据到最后面
            dataCache.splice(index, 1, item);
            item.diff[1] = newData.diff[1];
        }
    );
};
export class DrawEngine {
    /** 存放所有的 tile */
    g = new Graphics();
    data = new DataController([]);
    tileMap: TileMap;
    constructor(
        public width: number,
        public height: number,
        public tileSize: number
    ) {
        this.tileMap = new TileMap(width, height, tileSize, this.g);
        reDrawCollection.add(this.outputDrawCache);
        this.createG();
    }
    destroy() {
        reDrawCollection.delete(this.outputDrawCache);
        this.g.destroy();
    }

    /** 创建运行实例 */
    protected createG() {
        this.g.interactive = false; //响应交互
        this.g.interactiveChildren = false;
        this.g.buttonMode = false; //鼠标变手型
        this.g.sortableChildren = true;
        this.g.alpha = 1;
    }

    /** 只有当数据变动的时候才需要进行绘制 */
    needDraw = false;
    /** 最终的绘制接口 */
    protected outputDrawCache = () => {
        /** 进行混色和记录 */

        this.drawAll();
        if (this.needDraw) {
            /** 按需写入区块 */
            this.tileMap.drawMatrix();
            this.needDraw = false;
        }
    };

    /** 内部改变的接口,不会进行混色和记录 */
    replacePoint(x: number, y: number, color: number, alpha: number) {
        if (x > this.width - 1 || y > this.height - 1 || x < 0 || y < 0) return;
        this.tileMap.changeMatrix(x, y, [color, alpha]);
        this.needDraw = true;
    }

    /** 数据记录的锁 */
    protected HistoryRecord = false;
    /** 瞬时数据缓存 */
    protected HistoryCache = createDataCache();
    /** 记录一个行为 */
    startRecord() {
        this.HistoryRecord = true;
    }
    /** 结束并保存这个行为 */
    stopRecord() {
        this.HistoryRecord = false;
        if (this.HistoryCache.length) {
            const record = new Meta({
                user: "",
                change: [...this.HistoryCache],
            });
            this.HistoryCache.clear();
            this.data.save(record);
            console.log("保存记录");
        }
    }

    /**
     * 在画布上绘制一个点
     * 已经进行位置去重
     * @params alpha 0-1 表示透明度 -1 表示擦除
     * @param blend 使用画笔颜色混合，或者是直接覆盖
     */
    drawPoint(x: number, y: number, color: number, alpha: number, blend = 1) {
        //! 越界不变更
        if (x > this.width - 1 || y > this.height - 1 || x < 0 || y < 0) return;

        const [oldColor, oldAlpha] = this.tileMap.dataMatrix.get(x, y)!;
        if (oldColor === color && oldAlpha === alpha) return;
        this.drawSlices.push([x, y, oldColor, oldAlpha, color, alpha, blend]);
    }
    /** 收集一个时间段内的绘制数据,[x,y,color,alpha,color1,alpha1] */
    private drawSlices: number[][] = [];
    private slicesPositionCache = new Set<string>();
    private drawAll() {
        if (this.drawSlices.length) {
            // 采用分段描绘的方式
            // const changes = blendColors(this.drawSlices);

            const changes = AsBlendColors(this.drawSlices);

            changes.forEach(([x, y, oldColor, oldAlpha, color, alpha]) => {
                this.HistoryCache.push({
                    position: [x, y],
                    diff: [
                        [oldColor, oldAlpha],
                        [color, alpha],
                    ],
                });
                this.tileMap.changeMatrix(x, y, [color, alpha]);
                this.needDraw = true;
            });
            this.drawSlices = [];
            this.slicesPositionCache.clear();
        }
    }
}
